package com.learn.juc;

import java.util.concurrent.*;

/**
 * ClassName:ThreadPoolDemo
 * Package:com.learn.juc
 * Description:
 *
 * @Author:@郭先森
 * @Create:2025/7/28 - 18:38
 * @Version:v1.0
 */

/*
*线程池是一种线程的使用模式，线程过多会带来调度开销，进而影响缓存局部和整体的性能。而线程池维护着多个线程，等待着监督管理者
* 可分配并发任务，这就避免了短时间任务频繁创建和销毁线程的代价，可以保证内核充分利用，还能放置过分调度
*
*线程池的工作主要是控制运行的任务的数量，处理过程中将任务放入队列，然后在线程创建后启动这些任务，如果线程数量超过了最大数量，
* 超出数量的线程排队等候，等待其它线程执行完毕，再从队列中取出任务来执行
*Java中的线程池是通过Executor框架实现的，该框架中用到了Executor、Executors、ExecutorService、ThreadPoolExecutor
* 线程池的常用的使用方式：
* 一池N线程: Executors.newFixedThreadPool();
* 一个任务一个任务的执行，一池一线程: Executors.newSingleThreadExecutor();
* 根据需求创建，可扩容，遇强则强: Executors.newCachedThreadPool()
*
*
* */
public class ThreadPoolDemo {


    public static void main(String[] args) throws InterruptedException {
        //一池N线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        //假设一个银行有5个窗口，但是来了十个顾客
        for (int i = 0; i < 10; i++) {
            //执行
            executorService.execute(()->{
                System.out.println(Thread.currentThread().getName()+"正在办理业务");
            });
        }
        executorService.shutdown();

        TimeUnit.SECONDS.sleep(5);
        System.out.println("==========================");

        //一池一线程
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            //执行
            singleThreadExecutor.execute(()->{
                System.out.println(Thread.currentThread().getName()+"正在办理业务");//创建了10个，会自动根据需求来决定创建几个，如果是20个人，可能15个线程就够了
            });
        }
        singleThreadExecutor.shutdown();
        TimeUnit.SECONDS.sleep(5);
        System.out.println("==========================");
    //一池可扩容线程
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            //执行
            cachedThreadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"正在办理业务");
            });
        }
        cachedThreadPool.shutdown();
        //以上三个线程池底层都是用到了ThreadPoolExecutor，ThreadPoolExecutor的构造方法一共有七个参数
        //第一个参数为核心线程数量（常驻线程数量）
        //第二个参数为最大线程数量
        //第三个参数为保持存活时间
        //第四个参数为存活时间的单位（秒，还是分钟）
        //第五个参数是一个阻塞队列，比如说常驻线程数量已经用完了，别的请求过来会进入这个阻塞队列
        //第六个参数是一个线程工厂，用于创建参数
        //第七个参数是拒绝策略（假设常驻线程用完了，最大线程也用完了，阻塞队列也满了，那再来新的请求就会拒绝）

        //工作流程：当执行execute的时候，线程池中的线程才会被创建，会先到常驻线程中进行处理（假设常驻线程用完了，那么就放到阻塞队列，
        // 假设阻塞队列满了，才会根据最大线程数量去处理创建新的线程），假设常驻线程满了、阻塞队列满了、最大线程数也用完了，这个时候
        // 又来了新的请求，那么就会直接执行拒绝策略
        //JDK内置的拒绝策略有四种
        //AbortPolicy(默认)：直接抛出拒绝执行异常组织系统正常运行
        //CallerRunsPolicy:”调用者运行“一种调节机制，该策略既不会抛弃任务，也不会抛出异常，而是将某些任务回退到调用者，从而降低新任务的流量
        //DiscardOldestPolicy:抛弃队列中等待最久的任务，然后把当前任务加入队列中，常使再次提交当前的任务
        //DiscardPolicy:该策略默默的丢弃无法处理的任务，不做任何处理也不抛出异常，如果允许任务丢失，这是一种比较好的策略

    }
}
